package com.zzyl.serve.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.CodeGenerator;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.serve.domain.*;
import com.zzyl.serve.dto.*;
import com.zzyl.serve.mapper.*;
import com.zzyl.serve.service.*;
import com.zzyl.serve.vo.CheckInConfigVo;
import com.zzyl.serve.vo.CheckInDetailVo;
import com.zzyl.serve.vo.CheckInElderVo;
import com.zzyl.serve.vo.ElderFamilyVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;

/**
 * 入住Service业务层处理
 * 
 * @author chenming
 * @date 2025-04-29
 */
@Service
public class CheckInServiceImpl extends ServiceImpl<CheckInMapper, CheckIn> implements ICheckInService
{
    @Autowired
    private CheckInMapper checkInMapper;
    @Autowired
    private ElderMapper elderMapper;
    @Autowired
    private BedMapper bedMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private CheckInConfigMapper checkInConfigMapper;

    /**
     * 查询入住
     * 
     * @param id 入住主键
     * @return 入住
     */
    @Override
    public CheckIn selectCheckInById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询入住列表
     * 
     * @param checkIn 入住
     * @return 入住
     */
    @Override
    public List<CheckIn> selectCheckInList(CheckIn checkIn)
    {
        return checkInMapper.selectCheckInList(checkIn);
    }

    /**
     * 新增入住
     * 
     * @param checkIn 入住
     * @return 结果
     */
    @Override
    public int insertCheckIn(CheckIn checkIn)
    {
        return save(checkIn) ? 1 : 0;
    }

    /**
     * 修改入住
     * 
     * @param checkIn 入住
     * @return 结果
     */
    @Override
    public int updateCheckIn(CheckIn checkIn)
    {
        return updateById(checkIn) ? 1 : 0;
    }

    /**
     * 批量删除入住
     * 
     * @param ids 需要删除的入住主键
     * @return 结果
     */
    @Override
    public int deleteCheckInByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除入住信息
     * 
     * @param id 入住主键
     * @return 结果
     */
    @Override
    public int deleteCheckInById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 申请入住[涉及5张表操作]
     * @param checkInApplyDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(CheckInApplyDto checkInApplyDto) {
        //1.校验老人是否已入住，如果已入住，直接结束流程
        LambdaQueryWrapper<Elder> elderLambdaQueryWrapper = new LambdaQueryWrapper<>();
        CheckInElderDto checkInElderDto = checkInApplyDto.getCheckInElderDto();
        elderLambdaQueryWrapper.eq(Elder::getIdCardNo, checkInElderDto.getIdCardNo())
                .in(Elder::getStatus,1,4);
        Elder elder = elderMapper.selectOne(elderLambdaQueryWrapper);
        if (ObjectUtil.isNotEmpty(elder)){
            throw new BaseException("该老人已入住,请勿重复申请入住");
        }
        //2.如果没有入住，更新床位状态为已入住
        Long bedId = checkInApplyDto.getCheckInConfigDto().getBedId(); //根据床位id查询床位对象
        Bed bed = bedMapper.selectBedById(bedId);
        bed.setId(bedId);
        bed.setBedStatus(1);
        bedMapper.updateById(bed);

        //3.新增或更新老人基本信息
        elder=insertOrUpdateElder(checkInElderDto,bed);

        //4.新增签约办理
        insertContract(elder,checkInApplyDto.getCheckInContractDto(),checkInApplyDto.getCheckInConfigDto());

        //5.新增入住信息(同时保存家属信息到remark字段)
        CheckIn checkIn = insertCheckInInfo(elder, bed, checkInApplyDto.getCheckInConfigDto(), checkInApplyDto.getElderFamilyDtoList());

        //6.新增入住配置
        insertCheckInConfig(checkIn,checkInApplyDto.getCheckInConfigDto());

    }

    @Autowired
    private IElderService elderService;
    @Autowired
    private IBedService bedService;
    @Autowired
    private IContractService contractService;
    @Autowired
    private ICheckInConfigService checkInConfigService;
    //新增申请入住上课方法
    /*@Override
    @Transactional
    public void apply(CheckInApplyDto dto){
        //1.判断老人是否已经入住
        //1.1通过身份证号、状态，查询老人
        Elder elder=elderService.getOne(
                new LambdaQueryWrapper<Elder>()
                        .eq(Elder::getIdCardNo,dto.getCheckInElderDto().getIdCardNo())
                        .eq(Elder::getStatus,1)
        );
        //1.2判断老人是否入住：如果查询不为空，这抛出异常，终止运行：如果没有查询到，才能开始后续的入住流程
        if (ObjectUtil.isNotEmpty(elder)){
            //说明老人已经是入住状态，不能新增了，抛出异常，终止运行
            throw new RuntimeException("该老人已入住,请勿重复申请入住");
        }

        //2.更新床位的状态已入住
        //2.1通过床位id，查询床位
        Bed bed=bedService.getById(dto.getCheckInConfigDto().getBedId());
        if (bed==null){
            throw new RuntimeException("该床位不存在，请重新选择");
        }
        //2.2更新床位状态为已入住
        bed.setBedStatus(1);
        bedService.updateById(bed);

        //3.保存或更新老人基本信息
        //3.1准备老人数据，属性拷贝，设置床位号、设置床位id、设置老人状态
        elder=new Elder();
        BeanUtils.copyProperties(dto.getCheckInElderDto(), elder);

        elder.setBedNumber(bed.getBedNumber());
        elder.setBedId(bed.getId());
        elder.setStatus(1);
        //3.2查询老人信息(身份证号，状态不为1)
        Elder elderDb=elderService.getOne(
                new LambdaQueryWrapper<Elder>()
                        .eq(Elder::getIdCardNo,dto.getCheckInElderDto().getIdCardNo())
                        .ne(Elder::getStatus,1)
        );
        //3.3判断老人信息：如果查询到，则更新，否则保存
        if (elderDb!=null){
            //之前有入住记录，修改状态即可
            elder.setId(elderDb.getId());
            elderService.updateById(elder);
        }else {
            //之前没有记录，新增老人信息
            elderService.save(elder);
        }

        //4.新增签约办理（保存合同信息）
        //4.1.生成合同编号：（使用工具类生成一个16位的合同编号）
        String constractNumber = "HT"+CodeGenerator.generateContractNumber();

        //4.2保存合同信息（设置属性，合同号、老人id、老人名字、计算时间设置状态，合同开始结束时间，插入保存）
        Contract contract = new Contract();
        BeanUtils.copyProperties(dto.getCheckInContractDto(), contract);

        contract.setContractNumber(constractNumber);
        contract.setElderId(elder.getId());
        contract.setElderName(elder.getName());
        //开始时间结束时间需要从configDto获取
        LocalDateTime startDate=dto.getCheckInConfigDto().getStartDate();
        LocalDateTime endDate=dto.getCheckInConfigDto().getEndDate();
        contract.setStartDate(startDate);
        contract.setEndDate(endDate);
//        合同的状态要进行时间判断：
//        结束>当前时间>合同的开始时==>生效
//        当前时间<合同的开始时==>未生效
//        当前时间>结束时间==>已过期
        if (LocalDateTime.now().isBefore(startDate)){
            //当前时间<合同的开始时==>未生效
            contract.setStatus(0);
        }else {
            //当前时间>合同的开始时==>生效
            contract.setStatus(1);
        }
        //执行新增
        contractService.save(contract);

        //5.新增入住信息（设置属性，插入保存）
        CheckIn checkIn = new CheckIn();
        BeanUtils.copyProperties(dto.getCheckInConfigDto(), checkIn);
        checkIn.setElderId(elder.getId());
        checkIn.setElderName(elder.getName());
        checkIn.setIdCardNo(elder.getIdCardNo());
        checkIn.setBedNumber(bed.getBedNumber());
        checkIn.setStatus(0L);
        // 特别说明： 需要将老人家属封装 remark中 json存储
        checkIn.setRemark(JSON.toJSONString(dto.getElderFamilyDtoList()));
        this.save(checkIn);

        //6．新增入住配置信息：（属性拷贝，设置关联id，插入保存）
        CheckInConfig checkInConfig = new CheckInConfig();
        BeanUtils.copyProperties(dto.getCheckInConfigDto(), checkInConfig);
        checkInConfig.setCheckInId(checkIn.getId());
        checkInConfigService.save(checkInConfig);
    }*/

    /**
     * 查询入住详情
     * @param id
     * @return
     */
    /*@Override
    public CheckInDetailVo detail(Long id) {
        //将数据库里的入住详细信息封装到CheckInDetailVo中,其中包含checkInElderVo，elderFamilyVoList,CheckInConfigVo,contract;再返回给前端
        CheckInDetailVo checkInDetailVo = new CheckInDetailVo();

        //通过id查询checkIn,获取到其中的elderId,设置wrapper看elder的id是否与checkIn的elderId相同，通过elderId查询elder信息,相等则进行属性拷贝，封装到checkInElderVo中
        CheckIn checkIn = checkInMapper.selectCheckInById(id);
        CheckInElderVo checkInElderVo = new CheckInElderVo();
        if (checkIn.getElderId().equals(checkIn.getElderId())) {
            Elder elder = elderMapper.selectElderById(checkIn.getElderId());
            BeanUtils.copyProperties(elder, checkInElderVo);

            //先根据checkIn中的身份证号idCardNo，
            String idCardNo = checkIn.getIdCardNo();
            // idCardNo与当前日期比较得到年龄,然后赋值给checkInElderVo的age属性
            // 确保身份证号长度正确
            if (idCardNo == null || idCardNo.length() != 18) {
                throw new IllegalArgumentException("身份证号码不正确");
            }
            // 提取出身份证号码中的出生日期部分
            String birthDateStr = idCardNo.substring(6, 14);
            // 将出生日期字符串转换成LocalDate对象
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDate birthDate = LocalDate.parse(birthDateStr, formatter);
            // 获取当前日期
            LocalDate currentDate = LocalDate.now();
            int age = Period.between(birthDate, currentDate).getYears();
            checkInElderVo.setAge(age);

            checkInDetailVo.setCheckInElderVo(checkInElderVo);
        }
        //拿到老人的id赋值给elderId
        Long elderId = checkIn.getElderId();


        //通过id查询，从checkIn.remark拿到家属信息放到elderFamilyVoList中
        List<ElderFamilyVo> elderFamilyVoList = new ArrayList<>();
        checkInDetailVo.setElderFamilyVoList(elderFamilyVoList);
        String remark = checkInMapper.selectCheckInById(id).getRemark();
        if (StringUtils.isNotBlank(remark)) {
            List<ElderFamilyDto> elderFamilyDtoList = JSON.parseArray(remark, ElderFamilyDto.class);
            for (ElderFamilyDto dto : elderFamilyDtoList) {
                ElderFamilyVo elderFamilyVo = new ElderFamilyVo();
                BeanUtils.copyProperties(dto, elderFamilyVo);
                elderFamilyVoList.add(elderFamilyVo);
            }
            checkInDetailVo.setElderFamilyVoList(elderFamilyVoList);
        }

        //通过id查询，获取入住配置信息,封装到checkInConfigVo
        CheckInConfigVo checkInConfigVo = new CheckInConfigVo();
        //设置wrapper，通过传入的id比较checkInConfig的checkInId和传入的id是否相等，相等则进行属性拷贝，设置checkInConfigVo
        CheckInConfig checkInConfig = checkInConfigMapper.selectOne(
                new LambdaQueryWrapper<CheckInConfig>()
                        .eq(CheckInConfig::getCheckInId, id)
        );
        if (checkInConfig != null){
            BeanUtils.copyProperties(checkInConfig, checkInConfigVo);
        }
        //调用checkIn里的startDate,endDate，设置checkInConfigVo
        checkInConfigVo.setStartDate(checkIn.getStartDate());
        checkInConfigVo.setEndDate(checkIn.getEndDate());
        checkInDetailVo.setCheckInConfigVo(checkInConfigVo);

        //设置wrapper，通过elder与contract的elderId比较是否相等，相等则进行属性拷贝，获取签约办理信息,封装到contract
        Contract contract = contractMapper.selectOne(
                new LambdaQueryWrapper<Contract>()
                        .eq(Contract::getElderId, elderId)
        );
        checkInDetailVo.setContract(contract);

        return checkInDetailVo;
    }*/


    /**
     * 查询入住详情
     * @param id
     * @return 入住详情(视频方法)
     */
    @Override
    public CheckInDetailVo detail(Long id) {
        //准备结果对象
        CheckInDetailVo checkInDetailVo = new CheckInDetailVo();
        //1.设置入住配置响应信息
        CheckInConfigVo checkInConfigVo = new CheckInConfigVo();
        CheckIn checkIn = checkInMapper.selectById(id);
        BeanUtils.copyProperties(checkIn, checkInConfigVo);

        CheckInConfig checkInConfig = checkInConfigMapper.selectOne(
                new LambdaQueryWrapper<CheckInConfig>()
                        .eq(CheckInConfig::getCheckInId, id)
        );
        if (checkInConfig != null){
            BeanUtils.copyProperties(checkInConfig, checkInConfigVo);
        }
        checkInDetailVo.setCheckInConfigVo(checkInConfigVo);

        //2.设置老人信息
        CheckInElderVo checkInElderVo = new CheckInElderVo();
        //获取老人id
        Long elderId = checkIn.getElderId();
        Elder elder = elderMapper.selectById(elderId);
        BeanUtils.copyProperties(elder, checkInElderVo);

        //也可以从出生日期获取年龄
//        checkInElderVo.setAge(DateUtil.ageOfNow(elder.getBirthday()));
        //从身份证中获取年龄
        checkInElderVo.setAge(IdcardUtil.getAgeByIdCard(elder.getIdCardNo()));
        checkInDetailVo.setCheckInElderVo(checkInElderVo);

        //3.设置家属响应信息
        String remark = checkIn.getRemark();
        //把对象变成JSON字符串是toJSONString()
        List<ElderFamilyVo> elderFamilyVos = JSON.parseArray(remark, ElderFamilyVo.class);
        checkInDetailVo.setElderFamilyVoList(elderFamilyVos);

        //4.设置签约办理信息
        Contract contract = contractMapper.selectOne(
                new LambdaQueryWrapper<Contract>()
                        .eq(Contract::getElderId, elderId)
        );
        checkInDetailVo.setContract(contract);

        return checkInDetailVo;
    }

    /**
     * 保存入住配置信息
     * @param checkIn
     * @param checkInConfigDto
     */
    private void insertCheckInConfig(CheckIn checkIn, CheckInConfigDto checkInConfigDto) {
        CheckInConfig checkInConfig = new CheckInConfig();
        checkInConfig.setCheckInId(checkIn.getId());
        BeanUtils.copyProperties(checkInConfigDto, checkInConfig);

        checkInConfigMapper.insert(checkInConfig);
    }

    /**
     * 新增入住信息
     * @param elder
     * @param bed
     * @param checkInConfigDto
     * @param elderFamilyDtoList
     */
    private CheckIn insertCheckInInfo(Elder elder, Bed bed, CheckInConfigDto checkInConfigDto, List<ElderFamilyDto> elderFamilyDtoList) {
        CheckIn checkIn = new CheckIn();
        checkIn.setElderName(elder.getName());
        checkIn.setElderId(elder.getId());
        checkIn.setIdCardNo(elder.getIdCardNo());
        checkIn.setStartDate(checkInConfigDto.getStartDate());
        checkIn.setEndDate(checkInConfigDto.getEndDate());

        checkIn.setNursingLevelName(checkInConfigDto.getNursingLevelName());
        checkIn.setBedNumber(bed.getBedNumber());
//        checkIn.setStatus(0);//有默认值
        //老人家属信息
        checkIn.setRemark(JSON.toJSONString(elderFamilyDtoList));
//        JSON.parseObject(JSON.toJSONString(elderFamilyDtoList));//解析这么用

        checkInMapper.insert(checkIn);
        return checkIn;
    }

    /**
     * 新增合同，签约办理
     * @param elder 老人信息
     * @param checkInContractDto 合同信息
     * @param checkInConfigDto 入住配置信息
     */
    private void insertContract(Elder elder, CheckInContractDto checkInContractDto, CheckInConfigDto checkInConfigDto) {
        Contract contract = new Contract();
        contract.setElderId(elder.getId());
        BeanUtils.copyProperties(checkInContractDto, contract);
        //生成一个合同编号
        String contractNumber = CodeGenerator.generateContractNumber();
        contract.setContractNumber(contractNumber);

        contract.setElderName(elder.getName());
        contract.setStartDate(checkInConfigDto.getStartDate());
        contract.setEndDate(checkInConfigDto.getEndDate());
        // 假设一开始合同状态都为0未生效,有默认值
//        contract.setStatus(0);
//        contract.setSortOrder();//不重要先不弄

        contractMapper.insert(contract);
    }

    /**
     * 新增或更新老人基本信息
     */
    private Elder insertOrUpdateElder(CheckInElderDto checkInElderDto, Bed bed) {
        //1.根据身份证号查询老人信息,判断新增还是更新
        String idCardNo = checkInElderDto.getIdCardNo();
        Elder elder = elderMapper.selectOne(new LambdaQueryWrapper<Elder>().eq(Elder::getIdCardNo, idCardNo));

        if (ObjectUtil.isNotEmpty(elder)){
            //更新老人信息
            //更新前端传过来的其他基本信息
            BeanUtils.copyProperties(checkInElderDto, elder);
            //更新床位信息
            elder.setBedId(bed.getId());
            elder.setBedNumber(bed.getBedNumber());
            elderMapper.updateById(elder);
        }else {
            //新增老人信息
            elder = new Elder();
            elder.setStatus(1);
            BeanUtils.copyProperties(checkInElderDto, elder);
            elder.setBedId(bed.getId());
            elder.setBedNumber(bed.getBedNumber());
            elderMapper.insert(elder);
        }
        return elder;
    }
}
